package com.ssy.lingxi.member.merchant.serviceimpl.base;

import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;
import com.ssy.lingxi.common.constant.Constants;
import com.ssy.lingxi.common.constant.basic.UserLoginSourceEnum;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.model.dto.MemberAndRoleIdDTO;
import com.ssy.lingxi.common.model.dto.UserLoginCacheDTO;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.utils.Aes128Util;
import com.ssy.lingxi.component.redis.service.IRedisUtils;
import com.ssy.lingxi.dataauth.model.constant.DataAuthConstant;
import com.ssy.lingxi.dataauth.model.dto.ChannelAuthDto;
import com.ssy.lingxi.dataauth.model.dto.ChannelAuthMemberDto;
import com.ssy.lingxi.dataauth.model.dto.DataAuthDto;
import com.ssy.lingxi.member.merchant.config.ServiceConfig;
import com.ssy.lingxi.member.merchant.config.ServiceVariable;
import com.ssy.lingxi.member.merchant.entity.MemberDO;
import com.ssy.lingxi.member.merchant.entity.MemberRoleDO;
import com.ssy.lingxi.member.merchant.entity.MemberUserDO;
import com.ssy.lingxi.member.merchant.entity.RoleDO;
import com.ssy.lingxi.member.merchant.model.bo.AuthCodeBO;
import com.ssy.lingxi.member.merchant.model.bo.AuthCodeMemberBO;
import com.ssy.lingxi.member.merchant.service.base.IBaseMemberCacheService;
import com.ssy.lingxi.member.merchant.service.base.IBaseMemberOrganizationService;
import com.ssy.lingxi.member.merchant.utils.NumberUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 会员用户缓存工具类实现
 * @author 万宁
 * @version 2.0.0
 * @date 2020-07-03
 */
@Service
public class BaseMemberCacheServiceImpl implements IBaseMemberCacheService {

    private static final Logger log = LoggerFactory.getLogger(BaseMemberCacheServiceImpl.class);

    @Resource
    private IRedisUtils redisUtils;

    @Resource
    private IBaseMemberOrganizationService baseMemberOrganizationService;

    /**
     * 缓存会员注册手机号，邮箱的后缀
     */
    private final String MEMBER_REGISTER_KEY_SUFFIX = "_reg";

    /**
     * 获取用户信息
     *
     * @param headers Http头部信息
     * @return 用户信息实体
     */
    @Override
    public UserLoginCacheDTO checkUserFromCache(HttpHeaders headers) {
        //HTTP header是否包含了token字段
        if (!headers.containsKey(ServiceConfig.USER_TOKEN_HTTP_HEADERS_KEY)) {
            throw new BusinessException(ResponseCode.TOKEN_DOES_NOT_EXIST_IN_CACHE);
        }

        //HTTP header是否包含了source字段
        if (!headers.containsKey(ServiceConfig.USER_LOGIN_SOURCE_HTTP_HEADERS_KEY)) {
            throw new BusinessException(ResponseCode.REQUEST_HEADER_ERROR);
        }

        //HTTP header的token字段是否为空
        String token = headers.getFirst(ServiceConfig.USER_TOKEN_HTTP_HEADERS_KEY);
        if (!StringUtils.hasLength(token)) {
            throw new BusinessException(ResponseCode.TOKEN_DOES_NOT_EXIST_IN_CACHE);
        }

        //HTTP header的source字段是否为空
        String source = headers.getFirst(ServiceConfig.USER_LOGIN_SOURCE_HTTP_HEADERS_KEY);
        if (!StringUtils.hasLength(source) || !UserLoginSourceEnum.toStringList().contains(source)) {
            throw new BusinessException(ResponseCode.REQUEST_HEADER_ERROR);
        }

        //redis中是否有token
        Object tokenObj = redisUtils.get(token, Constants.REDIS_USER_INDEX);
        if (tokenObj == null) {
            throw new BusinessException(ResponseCode.TOKEN_DOES_NOT_EXIST_IN_CACHE);
        }

        UserLoginCacheDTO cacheDTO = JSONUtil.parse(tokenObj).toBean(UserLoginCacheDTO.class);

        //用户信息反序列化是否成功
        if (cacheDTO == null) {
            throw new BusinessException(ResponseCode.TOKEN_DOES_NOT_EXIST_IN_CACHE);
        }

        // source字段是否与登录后缓存的loginFrom字段相同
        if (!cacheDTO.getLoginSource().equals(Integer.valueOf(source))) {
            throw new BusinessException(ResponseCode.LOGIN_SOURCE_NOT_EQUALS_TO_HTTP_HEADER_SOURCE);
        }

        return cacheDTO;
    }


    /**
     * 根据token，删除缓存的用户信息
     *
     * @param token 用户Token
     */
    @Override
    public void deleteUserToken(String token) {
        redisUtils.del(token, Constants.REDIS_USER_INDEX);
    }

    /**
     * 是否从平台后台登录
     * @param headers HttpHeaders信息
     * @return 用户信息
     */
    @Override
    public UserLoginCacheDTO needLoginFromManagePlatform(HttpHeaders headers) {
        UserLoginCacheDTO loginCacheDTO = checkUserFromCache(headers);
        if (loginCacheDTO.getLoginSource() == null || !loginCacheDTO.getLoginSource().equals(UserLoginSourceEnum.BUSINESS_MANAGEMENT_PLATFORM.getCode())) {
            throw new BusinessException(ResponseCode.NEED_LOGIN_FROM_MANAGE_PLATFORM);
        }
        return loginCacheDTO;
    }

    /**
     * 是否从业务平台登录
     * @param headers HttpHeaders信息
     * @return 用户信息
     */
    @Override
    public UserLoginCacheDTO needLoginFromBusinessPlatform(HttpHeaders headers) {
        UserLoginCacheDTO loginCacheDTO = checkUserFromCache(headers);
        if (loginCacheDTO.getLoginSource() == null || !loginCacheDTO.getLoginSource().equals(UserLoginSourceEnum.BUSINESS_WEB.getCode())) {
            throw new BusinessException(ResponseCode.NEED_LOGIN_FROM_BUSINESS_CENTER);
        }
        return loginCacheDTO;
    }

    /**
     * 是否从App客户端登录
     *
     * @param headers HttpHeaders信息
     * @return 缓存的用户信息
     */
    @Override
    public UserLoginCacheDTO needLoginFromMobile(HttpHeaders headers) {
        UserLoginCacheDTO loginCacheDTO = checkUserFromCache(headers);
        if (loginCacheDTO.getLoginSource() == null || !loginCacheDTO.getLoginSource().equals(UserLoginSourceEnum.BUSINESS_MOBILE.getCode())) {
            throw new BusinessException(ResponseCode.NEED_LOGIN_FROM_BUSINESS_APP);
        }
        return loginCacheDTO;
    }

    /**
     * 校验Web端请求的HttpHeader参数是否合法
     * @param headers HttpHeaders信息
     */
    @Override
    public void checkWebRequestHeader(HttpHeaders headers) {
        String source = headers.getFirst(ServiceConfig.USER_LOGIN_SOURCE_HTTP_HEADERS_KEY);
        //HttpHeader中是否包含source = 1
        //web端要校验请求头的站点id
        if (!StringUtils.hasLength(source) || !source.equals(String.valueOf(UserLoginSourceEnum.BUSINESS_WEB.getCode()))
                || checkLongValue(headers, ServiceConfig.USER_LOGIN_SITE_HTTP_HEADERS_KEY)) {
            throw new BusinessException(ResponseCode.REQUEST_HEADER_ERROR);
        }
    }

    /**
     * 校验移动端请求的HttpHeader参数是否合法
     * @param headers HttpHeaders信息
     */
    @Override
    public void checkMobileRequestHeader(HttpHeaders headers) {
        String source = headers.getFirst(ServiceConfig.USER_LOGIN_SOURCE_HTTP_HEADERS_KEY);
        //HttpHeader中是否包含source = 2
        //移动端要校验请求头的站点id
        if (!StringUtils.hasLength(source) || !source.equals(String.valueOf(UserLoginSourceEnum.BUSINESS_MOBILE.getCode()))
                || checkLongValue(headers, ServiceConfig.USER_LOGIN_SITE_HTTP_HEADERS_KEY)) {
            throw new BusinessException(ResponseCode.REQUEST_HEADER_ERROR);
        }
    }

    /**
     * 校验平台后台请求的HttpHeader参数是否合法
     * @param headers HttpHeaders信息
     */
    @Override
    public void checkPlatformRequestHeader(HttpHeaders headers) {
        String source = headers.getFirst(ServiceConfig.USER_LOGIN_SOURCE_HTTP_HEADERS_KEY);
        //HttpHeader中是否包含source = 99
        //平台后台要校验请求头的站点id
        if (!StringUtils.hasLength(source) || !source.equals(String.valueOf(UserLoginSourceEnum.BUSINESS_MANAGEMENT_PLATFORM.getCode()))
                || checkLongValue(headers, ServiceConfig.USER_LOGIN_SITE_HTTP_HEADERS_KEY)) {
            throw new BusinessException(ResponseCode.REQUEST_HEADER_ERROR);
        }
    }

    /**
     * 从Http头部获取Long类型的字段值
     *
     * @param headers HttpHeaders信息
     * @param key     HttpHeaders中的Key
     * @return Long类型值
     */
    @Override
    public Long getLongValueFromRequestHeader(HttpHeaders headers, String key) {
        return NumberUtil.tryParseLong(headers.getFirst(key));
    }

    /**
     * 校验请求头的HttpHeader中是否包含Long类型的必要信息 如：站点id 或 商城id等
     *
     * @param headers HttpHeaders信息
     * @return 请求头中是否有合理的Long类型的字段
     */
    @Override
    public Boolean checkLongValue(HttpHeaders headers, String... keyNames) {
        if (keyNames != null && keyNames.length > 0) {
            for (String keyName : keyNames) {
                Long value = NumberUtil.tryParseLong(headers.getFirst(keyName));
                if (NumberUtil.isNullOrLteZero(value)) {
                    return true;
                }
            }
            return false;
        }
        return true;
    }

    /**
     * 缓存字符串类型的内容
     *
     * @param key            缓存的Key
     * @param content        缓存的内容
     * @param timeoutSeconds 缓存时间，单位：秒
     */
    @Override
    public void setString(String key, String content, Long timeoutSeconds) {
        redisUtils.set(key, content, timeoutSeconds, Constants.REDIS_USER_INDEX);
    }

    /**
     * 读取缓存的字符串
     *
     * @param key 缓存的Key
     * @return 如果缓存内容不存在，返回空字符串，否则返回缓存内容
     */
    @Override
    public String getString(String key) {
        if (!redisUtils.exists(key, Constants.REDIS_USER_INDEX)) {
            return "";
        }

        Object obj = redisUtils.get(key, Constants.REDIS_USER_INDEX);
        return obj == null ? "" : String.valueOf(obj);
    }

    /**
     * 删除缓存的字符串
     * @param key 缓存的字符串
     */
    @Override
    public void deleteString(String key) {
        redisUtils.del(key, Constants.REDIS_USER_INDEX);
    }

    /**
     * 会员/用户注册时，或创建用户时，缓存手机号或邮箱
     * @param phone 手机号
     * @param email 邮箱
     * @param isPlatformMember 是否平台后台会员
     */
    @Override
    public void setRegisterKey(String phone, String email, Boolean isPlatformMember) {
        if (StringUtils.hasLength(phone)) {
            String key = phone.concat(isPlatformMember ? "_1" : "_0").concat(MEMBER_REGISTER_KEY_SUFFIX);
            boolean isSuccess = redisUtils.set(key, 1, ServiceConfig.REGISTER_PHONE_EMAIL_CACHE_SECONDS, Constants.REDIS_USER_INDEX);
            if (!isSuccess) {
                return;
            }
        }

        if (StringUtils.hasLength(email)) {
            String key = email.concat(isPlatformMember ? "_1" : "_0").concat(MEMBER_REGISTER_KEY_SUFFIX);
            redisUtils.set(key, 1, ServiceConfig.REGISTER_PHONE_EMAIL_CACHE_SECONDS, Constants.REDIS_USER_INDEX);
        }

    }

    /**
     * 会员/用户注册时，缓存手机号或邮箱或账号
     * @param phone 手机号
     * @param email 邮箱
     * @param account 账号
     * @param isPlatformMember 是否平台后台会员
     */
    @Override
    public void setRegisterKey(String phone, String email, String account, Boolean isPlatformMember) {
        if (StringUtils.hasLength(phone)) {
            String key = phone.concat(isPlatformMember ? "_1" : "_0").concat(MEMBER_REGISTER_KEY_SUFFIX);
            boolean isSuccess = redisUtils.set(key, 1, ServiceConfig.REGISTER_PHONE_EMAIL_CACHE_SECONDS, Constants.REDIS_USER_INDEX);
            if (!isSuccess) {
                return;
            }
        }

        if (StringUtils.hasLength(account)) {
            String key = account.concat(isPlatformMember ? "_1" : "_0").concat(MEMBER_REGISTER_KEY_SUFFIX);
            boolean isSuccess = redisUtils.set(key, 1, ServiceConfig.REGISTER_PHONE_EMAIL_CACHE_SECONDS, Constants.REDIS_USER_INDEX);
            if (!isSuccess) {
                return;
            }
        }

        if (StringUtils.hasLength(email)) {
            String key = email.concat(isPlatformMember ? "_1" : "_0").concat(MEMBER_REGISTER_KEY_SUFFIX);
            redisUtils.set(key, 1, ServiceConfig.REGISTER_PHONE_EMAIL_CACHE_SECONDS, Constants.REDIS_USER_INDEX);
        }
    }


    /**
     * 缓存的Key是否存在
     *
     * @param phoneOrEmail 手机号或邮箱
     * @param isPlatformMember 是否平台后台会员
     * @return true/false
     */
    @Override
    public Boolean existRegisterKey(String phoneOrEmail, Boolean isPlatformMember) {
        String key = phoneOrEmail.concat(isPlatformMember ? "_1" : "_0").concat(MEMBER_REGISTER_KEY_SUFFIX);
        return redisUtils.exists(key, Constants.REDIS_USER_INDEX);
    }

    /**
     * 删除缓存的用户手机号或邮箱
     * @param phone 缓存的手机号
     * @param email 缓存的邮箱
     * @param isPlatformMember 是否平台后台会员
     */
    @Override
    public void deleteRegisterKey(String phone, String email, Boolean isPlatformMember) {
        if (StringUtils.hasLength(phone)) {
            String key = phone.concat(isPlatformMember ? "_1" : "_0").concat(MEMBER_REGISTER_KEY_SUFFIX);
            redisUtils.del(key, Constants.REDIS_USER_INDEX);
        }

        if (StringUtils.hasLength(email)) {
            String key = email.concat(isPlatformMember ? "_1" : "_0").concat(MEMBER_REGISTER_KEY_SUFFIX);
            redisUtils.del(key, Constants.REDIS_USER_INDEX);
        }
    }

    /**
     * 删除缓存的用户手机号或邮箱或账号
     * @param phone 缓存的手机号
     * @param email 缓存的邮箱
     * @param account 缓存的账号
     * @param isPlatformMember 是否平台后台会员
     */
    @Override
    public void deleteRegisterKey(String phone, String email, String account, Boolean isPlatformMember) {
        if (StringUtils.hasLength(phone)) {
            String key = phone.concat(isPlatformMember ? "_1" : "_0").concat(MEMBER_REGISTER_KEY_SUFFIX);
            redisUtils.del(key, Constants.REDIS_USER_INDEX);
        }

        if (StringUtils.hasLength(email)) {
            String key = email.concat(isPlatformMember ? "_1" : "_0").concat(MEMBER_REGISTER_KEY_SUFFIX);
            redisUtils.del(key, Constants.REDIS_USER_INDEX);
        }

        if (StringUtils.hasLength(account)) {
            String key = account.concat(isPlatformMember ? "_1" : "_0").concat(MEMBER_REGISTER_KEY_SUFFIX);
            redisUtils.del(key, Constants.REDIS_USER_INDEX);
        }
    }

    /**
     * 用户登录后，缓存登录信息
     *
     * @param loginSource           用户登录来源
     * @param memberLevelTypeEnum   会员等级类型
     * @param memberUserDO          登录用户
     * @param memberDO              会员
     * @param roleDO                登录的角色
     * @param upperChannelMemberIds 上级渠道会员Id列表
     * @param upperVendorMembers    上级服务提供者会员列表
     * @param subVendorMembers      下级服务提供者会员列表
     * @param subChannelMembers     下级渠道会员Id列表
     * @param accessUrlList         可访问的前端页面UrlCode列表
     * @param token                 用户token
     * @param siteId                登录站点Id
     * @param shopId                登录商城Id
     * @param level                 会员等级
     */
    @Override
    public void cacheUserInfo(UserLoginSourceEnum loginSource, Integer memberLevelTypeEnum, MemberUserDO memberUserDO, MemberDO memberDO, RoleDO roleDO, List<Long> upperChannelMemberIds, List<MemberAndRoleIdDTO> upperVendorMembers, List<MemberAndRoleIdDTO> subVendorMembers, List<MemberAndRoleIdDTO> subChannelMembers, List<String> accessUrlList, String token, Long siteId, Long shopId, Integer level) {
        UserLoginCacheDTO loginCache = new UserLoginCacheDTO();
        loginCache.setUserId(memberUserDO.getId());
        loginCache.setUserType(memberUserDO.getTypeEnum());
        loginCache.setLoginSource(loginSource.getCode());
        loginCache.setLoginTime(System.currentTimeMillis());
        loginCache.setTokenExpireMinutes(ServiceVariable.WEB_LOGIN_TOKEN_EXPIRE_MINUTES);
        loginCache.setUserName(StringUtils.hasLength(memberUserDO.getName()) ? memberUserDO.getName() : "");
        loginCache.setUserPhone(memberUserDO.getPhone());
        loginCache.setUserJobTitle(StringUtils.hasLength(memberUserDO.getJobTitle()) ? memberUserDO.getJobTitle() : "");
        loginCache.setLogo(StringUtils.hasLength(memberUserDO.getLogo()) ? memberUserDO.getLogo() : "");
        loginCache.setUserOrgName(memberUserDO.getOrg() == null ? "" : memberUserDO.getOrg().getTitle());
        loginCache.setUserRoleName(CollectionUtils.isEmpty(memberUserDO.getRoles()) ? "" : memberUserDO.getRoles().stream().map(MemberRoleDO::getRoleName).collect(Collectors.joining(",")));

        loginCache.setAccessUrlList(accessUrlList);

        loginCache.setMemberId(memberDO.getId());
        loginCache.setCompany(memberDO.getName());
        loginCache.setMemberLevelType(memberLevelTypeEnum);
        loginCache.setMemberType(roleDO.getMemberType().getTypeEnum());
        loginCache.setMemberRoleType(roleDO.getRoleType().getTypeEnum());
        loginCache.setMemberRoleId(roleDO.getId());
        loginCache.setMemberRoleName(roleDO.getRoleName());

        loginCache.setUpperChannelMemberIds(upperChannelMemberIds);
        loginCache.setUpperVendorMembers(upperVendorMembers);
        loginCache.setSubVendorMembers(subVendorMembers);
        loginCache.setSubChannelMembers(subChannelMembers);

        //门店id
        loginCache.setStoreIds(baseMemberOrganizationService.getMemberOrgStoreIds(memberUserDO, memberDO.getId()).stream().distinct().collect(Collectors.toList()));
        //站点Id
        loginCache.setSiteId(siteId);
        //商城Id
        loginCache.setShopId(shopId);
        //平台会员等级(不是当前登录用户在不同供应商的会员等级)
        loginCache.setLevel(level);

        long tokenExpireSeconds;
        switch (loginSource) {
            case BUSINESS_WEB:
            case BUSINESS_MANAGEMENT_PLATFORM:
                tokenExpireSeconds = ServiceVariable.WEB_LOGIN_TOKEN_EXPIRE_MINUTES * 60;
                break;
            case BUSINESS_MOBILE:
                tokenExpireSeconds = ServiceConfig.MOBILE_LOGIN_TOKEN_EXPIRE_MINUTES * 60;
                break;
            default:
                tokenExpireSeconds = 0;
                break;
        }

        redisUtils.set(token, loginCache, tokenExpireSeconds, Constants.REDIS_USER_INDEX);

        //数据权限
        if (!CollectionUtils.isEmpty(memberUserDO.getUserAuth().getDataAuth())) {
            String dataAuthKey = String.format(DataAuthConstant.DATA_AUTH_CACHE_KEY_FORMAT, token, memberUserDO.getId(), loginSource.getCode());
            memberUserDO.getUserAuth().getDataAuth().stream().filter(dataAuthBO -> dataAuthBO.getSource().equals(loginSource.getCode())).forEach(dataAuthBO -> {
                DataAuthDto dataAuthDto = new DataAuthDto();
                dataAuthDto.setDataAuth(true);
                dataAuthDto.setUserIds(dataAuthBO.getUserIds());
                redisUtils.hSet(dataAuthKey, dataAuthBO.getUrl(), dataAuthDto, tokenExpireSeconds, Constants.REDIS_USER_INDEX);
            });
        }

        //渠道权限
        if (!CollectionUtils.isEmpty(memberUserDO.getUserAuth().getChannelAuth())) {
            List<ChannelAuthMemberDto> channelAuthMemberDtoList = memberUserDO.getUserAuth().getChannelAuth().stream().filter(channelAuthBO -> subChannelMembers.stream().anyMatch(subChannel -> subChannel.getMemberId().equals(channelAuthBO.getMemberId()) && subChannel.getRoleId().equals(channelAuthBO.getRoleId()))).map(channelAuthBO -> {
                ChannelAuthMemberDto channelAuthMemberDto = new ChannelAuthMemberDto();
                channelAuthMemberDto.setMemberId(channelAuthBO.getMemberId());
                channelAuthMemberDto.setRoleId(channelAuthBO.getRoleId());
                return channelAuthMemberDto;
            }).collect(Collectors.toList());

            if (!CollectionUtils.isEmpty(channelAuthMemberDtoList)) {
                String channelAuthKey = String.format(DataAuthConstant.CHANNEL_AUTH_CACHE_KEY_FORMAT, token, memberUserDO.getId());
                ChannelAuthDto channelAuthDto = new ChannelAuthDto();
                channelAuthDto.setChannels(channelAuthMemberDtoList);
                redisUtils.set(channelAuthKey, channelAuthDto, tokenExpireSeconds, Constants.REDIS_USER_INDEX);
            }
        }
    }

    @Override
    public AuthCodeBO createAuthCode() {
        // 生成授权码
        String authCode = IdUtil.simpleUUID();

        // 缓存
        String key = Constants.QR_AUTH_CODE_SUFFIX + authCode;
        if (redisUtils.exists(key, Constants.REDIS_USER_INDEX)) {
            authCode = IdUtil.simpleUUID();
        }

        long expireTime = Constants.QR_AUTH_CODE_EXPIRE_MINUTES * 60;
        redisUtils.set(key, key, expireTime, Constants.REDIS_USER_INDEX);

        // 加密, 为了让扫出二维码的信息不那么容易看出来,显得专业点
        try {
            authCode = Aes128Util.aesEncrypt(authCode);
        } catch (Exception e) {
            log.error("authCode AES加密错误", e);
            throw new BusinessException(ResponseCode.AES_ENCRYPTION_ERROR);
        }

        return new AuthCodeBO(authCode, expireTime);
    }

    @Override
    public void activeAuthCode(String authCode, UserLoginCacheDTO userLoginCacheDTO) {
        // 解密
        String deAuthCode = Aes128Util.tryAesDecrypt(authCode);

        // 校验authCode
        String authCodeKey = Constants.QR_AUTH_CODE_SUFFIX + deAuthCode;
        if (!redisUtils.exists(authCodeKey, Constants.REDIS_USER_INDEX)) {
            throw new BusinessException(ResponseCode.MC_MS_APP_LOGIN_AUTH_CODE_EXPIRE);
        }

        AuthCodeMemberBO authCodeMemberBO = new AuthCodeMemberBO();
        authCodeMemberBO.setMemberId(userLoginCacheDTO.getMemberId());
        authCodeMemberBO.setUserId(userLoginCacheDTO.getUserId());

        // 授权信息
        String authInfoKey = Constants.QR_AUTH_INFO_SUFFIX + deAuthCode;
        redisUtils.set(authInfoKey, authCodeMemberBO, Constants.QR_AUTH_CODE_EXPIRE_MINUTES * 60, Constants.REDIS_USER_INDEX);

        // authCode只能使用一次, 删除authCode
        redisUtils.del(authCodeKey, Constants.REDIS_USER_INDEX);
    }

    @Override
    public AuthCodeMemberBO getAuthDetail(String authCode) {
        // 解密
        String deAuthCode = Aes128Util.tryAesDecrypt(authCode);

        // 授权信息
        String key = Constants.QR_AUTH_INFO_SUFFIX + deAuthCode;
        AuthCodeMemberBO authCodeMemberBO = (AuthCodeMemberBO) redisUtils.get(key, Constants.REDIS_USER_INDEX);

        if (Objects.isNull(authCodeMemberBO)) {
            return null;
        }

        return authCodeMemberBO;
    }
}
